package util;

import java.util.*;

public class Hill {
    Character[] x = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
            'P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
            'o','p','q','r','s','t','u','v','w','x','y','z',',','.','\'','?','!','@','-','+','*','/','1','2','3','4',
            '5','6','7','8','9',' '};
    //创建映射表
    HashMap<Character,Integer> wordMap = new HashMap();
    HashMap<Integer,Character> numMap = new HashMap();

    public Hill(){
        for(int i = 0; i < x.length; i++){
            numMap.put(i,x[i]);
        }
        for(int i = 0; i < x.length; i++){
            wordMap.put(x[i],i);
        }
    }

    //获取密钥
    public int[][] getSecretKey(){
        ArrayList<String> keyArray = new ArrayList<String>();
        Scanner scanKey = new Scanner(System.in);
        System.out.println("please input a N x N matrix secret key(input x to finish input): ");
        String nextLine = scanKey.nextLine();
        while (!nextLine.equals("x")){
            keyArray.add(nextLine);
            nextLine = scanKey.nextLine();
        }
        System.out.println(keyArray);
        int arrarySize = keyArray.size();
        int [][] secretKey = new int[arrarySize][arrarySize];
        for (int i = 0 ; i < arrarySize; i++){
            String[] vec = keyArray.get(i).split(" ");
            for (int j = 0; j < arrarySize; j++){
                secretKey[i][j] = Integer.valueOf(vec[j]).intValue();
            }
        }
        return secretKey;
    }

    //获取密文或明文
    public String getText(){
        Scanner scanText = new Scanner(System.in);
        String text = new String();
        System.out.println("please input the text you want to encrypt or decrypt:");
        String nextLine = scanText.nextLine();
        while (nextLine != null && !nextLine.equals("")){
            text+=nextLine;
            nextLine = scanText.nextLine();
        }
        return text;
    }

    //加密
    public String Encrypt(String cleartext, Matrix_c secretKey){
        String cipherText = "";
        int splitLen = secretKey.len;            //分割长度
        int textLen = cleartext.length();
        int addLen = 0;
        if (textLen % splitLen != 0){
            addLen = splitLen - textLen % splitLen;            //需要补齐的长度
        }
        int splitTextLen = (textLen+addLen)/splitLen;
        String[] splitText = new String[splitTextLen];
        for (int i = 0; i < addLen; i++){
            cleartext+=' ';
        }
        for (int i = 0,j = 0; i <= textLen+addLen-splitLen; i=i+splitLen,j++){
            splitText[j] = cleartext.substring(i,i+splitLen);
        }

        Character[][] splitArray = new Character[splitTextLen][splitLen];

        for (int i = 0; i < splitText.length; i++){                     //转为字符数组
            for (int j = 0; j < splitLen; j++){
                splitArray[i][j] = splitText[i].charAt(j);
            }
        }

        int[][] splitArrayToInt = new int[splitTextLen][splitLen];    //将字符转为对应数字
        for (int i = 0; i < splitText.length; i++){
            for (int j = 0; j < splitLen; j++){
                splitArrayToInt[i][j] = wordMap.get(splitArray[i][j]);
            }
        }

        int[][] cipherArray = secretKey.MultplyMatrix(splitArrayToInt); //数字矩阵乘以密钥矩阵加密
        for (int[] i: cipherArray){
            for (int j : i){
                cipherText = cipherText + numMap.get(j%72) +" ";
            }
        }
        return cipherText;
    }

    //解密
    public String Decrypt(String cipherText,Matrix_c secretKey){
        int splitLen = secretKey.len;
        Character[] cipherArray = new Character[(cipherText.length())/2];
        for (int i = 0,j = 0; i < (cipherText.length()); i+=2,j++){
            cipherArray[j] = cipherText.charAt(i);
        }
        int[][] matrixArray = new int[cipherArray.length/splitLen][splitLen];
        for (int i = 0,j = 0; i < cipherArray.length; i+=splitLen,j++){
            for (int k =0; k < splitLen; k++)
                matrixArray[j][k] = wordMap.get(cipherArray[i + k]);  //将密文转为int矩阵
        }
        Matrix_c inversionKey = new Matrix_c();
        inversionKey.setValue(secretKey.getInversionMatrix(secretKey.matrix));
        String clearText = "";
        for (int i = 0; i < matrixArray.length; i++){                   //乘逆矩阵解密
            int[][] changeToTwoDimension = {matrixArray[i]};
            int[][] vec= inversionKey.MultplyMatrix(changeToTwoDimension);
            for (int[] j: vec){
                for (int k: j){
                    while(k<0){
                        k+=72;
                    }
                    clearText+=numMap.get(k%72);
                }
            }
        }
        return clearText;
    }
}
